//	--------------------------------------------------------------------
//	Copyright(C) 2006,2007 Zhao Yukun. All rights reserved.
//	This file is a part of the Xeres system.
//	Xeres 2007
//	Contact : xeres.engine@gmail.com
//	$(reservedInfo)
//	$(reservedDeclaration)
//	--------------------------------------------------------------------
///	@file	<ProfileConsole.cpp>
///	@path	~/e:\xeres\src\appear\xwin/
///	@date	2008/10/07
///	@brief	.


#define _FULLAPI
#include "config/config.h"

#include "engine/xcore/xeres_engine.h"
#include "engine/xcore/event_center.h"

#include "appear/xwin/ProfileConsole.h"



namespace xeres {

	// ProfileConsole
	ProfileConsole::ProfileConsole( void )
		: m_actived( false )
		, m_reset( false )
	{

	}

	// ~ProfileConsole
	ProfileConsole::~ProfileConsole( void )
	{

	}

	// Initialize
	bool ProfileConsole::Initialize( RefWeak<IData> root )
	{
		return true;
	}

	// Finalize
	void ProfileConsole::Finalize( void )
	{
		m_backgroundLayer = NULL;
		m_focusLayer = NULL;
		m_canvas = NULL;
		m_board = NULL;
		m_textFont = NULL;
	}

	namespace
	{
		struct _DebugCanvasVertex
		{
			FLOAT x, y, z, rhw; // The transformed position for the vertex.
			DWORD color;        // The vertex color.
		};
	}

	// PrepareConsoleResource
	void ProfileConsole::PrepareConsoleResource( RefWeak<IRenderer> renderer )
	{
		// Calculate regions.
		Rect<int> board( 30 , 30 , m_rect.right() - 30 , m_rect.bottom() - 30 );

		if( m_canvas.IsNull() )
		{
			// Create all new elements.
			m_canvas = new CCanvas;
			m_canvas->Initialize( renderer );

			m_textFont = renderer->CreateFont(
				_S("Courier New") , -14 , 0 , 400 , false , true , true );

			m_board = new CCanvasTextBoard( m_textFont , &m_lines );

			m_canvas->AddElement( m_board );
		}

		m_board->SetRect( board );

		_DebugCanvasVertex board_vert[] = {
			{ (float)m_rect.left()  , (float)m_rect.bottom() , 0.5f, 1.0f, 0xaa333333, },
			{ (float)m_rect.left()  , (float)m_rect.top()    , 0.5f, 1.0f, 0xaa333333, }, // x, y, z, rhw, color
			{ (float)m_rect.right() , (float)m_rect.bottom() , 0.5f, 1.0f, 0xaa333333, },
			{ (float)m_rect.right() , (float)m_rect.top()    , 0.5f, 1.0f, 0xaa333333, },
		};

// 		m_backgroundLayer = renderer->CreateSimplePolygon(
// 			GEOMETRY_TRISTRIP , SGV_POSITION_T | SGV_DIFFUSE , 4 , 
// 			board_vert , 0 , 0 );//s_debugCanvasIndecis );

		m_reset = false;

	}

	// UpdateFocusItem
	void ProfileConsole::UpdateFocusItem( RefWeak<IRenderer> renderer )
	{
		if( m_focusing < 0 || m_focusing >= (int)m_lines.size() )
		{
			m_focusing = 0;
			m_focusLayer = NULL;
			return;
		}

		int top = m_lines[m_focusing].top;
		int bottom = m_lines[m_focusing].bottom;

		Rect<int> rect( m_rect.left() , top , m_rect.right() , bottom );

		_DebugCanvasVertex focus_vert[] = {
			{ (float)rect.left()  , (float)rect.bottom() , 0.5f, 1.0f, 0x77ddaa33, },
			{ (float)rect.left()  , (float)rect.top()    , 0.5f, 1.0f, 0x77ddaa33, }, // x, y, z, rhw, color
			{ (float)rect.right() , (float)rect.bottom() , 0.5f, 1.0f, 0x00000000, },
			{ (float)rect.right() , (float)rect.top()    , 0.5f, 1.0f, 0x00000000, },
		};

// 		m_focusLayer = renderer->CreateSimplePolygon(
// 			GEOMETRY_TRISTRIP , SGV_POSITION_T | SGV_DIFFUSE , 4 , 
// 			focus_vert , 0 , 0 );//s_debugCanvasIndecis );
	}

	namespace
	{
		class ProfileObservation : public Observation
		{
		public:
			/// \ctor
			ProfileObservation( std::deque<TextBoardLine>& lines )
				: m_lines( lines ) , m_depth(0) , m_id(0)
			{
				m_root = ArithmeticOp<double>::nan();
			}

			/// \brief	Interface to accept observation data.
			virtual bool Visited( ObserverType type , Observer * observer , const WString& label )
			{
				if( type == OBSERVER_last )
				{
					--m_depth;
					return true;
				}

				static const int total = 60;
				wchar_t buf[total];
				int fill = m_depth * 2;
				int counter = total - fill - (int)label.size() - 30;
				double ms = boost::any_cast<double>(observer->GetValue());

				if( m_root == ArithmeticOp<double>::nan() )
					m_root = ms;

				wchar_t * p = buf;
				for( wchar_t * end = buf + fill ; p < end ; ++p )
					*p = ' ';
				swprintf( p , _S("%s:") , label.c_str() );
				p = buf + wcslen(buf);
				for( wchar_t * end = p + counter ; p < end ; ++p )
					*p = ' ';
				swprintf( p , _S(" %8.4f ms  ( %6.2f%% )") , ms , ms / m_root * 100 );

				TextBoardLine line;
				line.color = PackColor4( 0xffffffff );
				line.line = buf;
				m_lines.push_back( line );

				if( type == OBSERVER_DIR )
					++m_depth;

				return true;
			}
		private:
			std::deque<TextBoardLine>&	m_lines;
			double m_root;
			int m_depth;
			int m_id;
		};
	}

	// Tick
	void ProfileConsole::Tick( Engine& engine )
	{
		COUNTER_GUARD( _S("profile_overhead") );
		// handle canvas
		if( m_reset )
		{
			if( m_rect.width() > 0 && m_rect.height() > 0 )
			{
				// schedule engine to build canvas
//				engine.QueueSyncResourceCreator( bind( &ProfileConsole::PrepareConsoleResource , this , _1 ) );
			}
		}

		// update current dir
		m_lines.clear();

		// check
		ProfileObservation obs( m_lines );
		Observer::root()->VisitChildren( _S("counter/*") , bind( &ProfileObservation::Visited , &obs , _1 , _2 , _3 ) );
		
		// handle canvas
		if( m_canvas.IsNull() )
		{
			if( m_rect.width() > 0 && m_rect.height() > 0 )
			{
				// schedule engine to build canvas
//				engine.QueueSyncResourceCreator( bind( &ProfileConsole::PrepareConsoleResource , this , _1 ) );
			}
		}
	}

	// Render
	void ProfileConsole::Render( RenderContext& rc )
	{
		if( rc.ResX<int>() != m_rect.width() || rc.ResY<int>() != m_rect.height() )
		{
			// rebuild them
			m_reset = true;
			m_rect.set( 0 , 0 , rc.ResX<int>() , rc.ResY<int>() );
		}

		if( m_canvas.IsNull() )
			return;

		//COUNTER_SCOPE( _S("profile") );
		m_backgroundLayer->EstablishBuffer( rc );
		m_backgroundLayer->Draw( rc );

		if( m_focusLayer.IsValid() )
		{
			m_focusLayer->EstablishBuffer( rc );
			m_focusLayer->Draw( rc );
		}

		m_canvas->Render( rc );

		//COUNTER_END();
	}

	// OnKeyInput
	HandleInput ProfileConsole::OnKeyInput( const KeyInput& input )
	{
// 		if( input.IsReleased() )
// 		{
// 			switch( input.GetKey() )
// 			{
// 			case KeyInput::KEY_UPARROW:
// 				// move to next focus
// 				if( m_focusing > 0 )
// 					--m_focusing;
// 				else
// 					m_focusing = 0;
// 				return INPUT_HANDLED;
// 			case KeyInput::KEY_DOWNARROW:
// 				// move to previous focus
// 				++m_focusing;
// 				return INPUT_HANDLED;
// 
// 			case KeyInput::KEY_RETURN:
// 				// enter child
// 				return INPUT_HANDLED;
// 			} // switch key
// 		}
		return INPUT_UNHANDLED;
	}

	// OnMouseInput
	HandleInput ProfileConsole::OnMouseInput( const MouseInput& input )
	{
		return INPUT_UNHANDLED;
	}

	// OnActive
	void ProfileConsole::OnActive( bool is_active )
	{
		m_actived = is_active;

		if( m_actived )
		{
			TRACE_INFO( _S("Active outline console ... ") );
		}
		else
		{
			TRACE_INFO( _S("Deactive outline console ... ") );
		}
	}

} // namespace xeres
